#include "usb.h"
#include "usb_device.h"
#include "usb_device_class.h"
#include "usb_device_hid.h"
#include "usb_device_config.h"
#include "usb_device_ch9.h"
#include "usb_device_descriptor.h"
#include "usb_composite.h"
#include "usb_hid.h"

#if defined(USB_DEVICE_ENABLE_HID) && (USB_DEVICE_ENABLE_HID > 0)

USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t hid_rec_buffer[FS_HID_GENERIC_INTERRUPT_OUT_PACKET_SIZE];
USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) static uint8_t hid_send_buffer[FS_HID_GENERIC_INTERRUPT_OUT_PACKET_SIZE];
static usb_device_composite_struct_t *s_UsbDeviceComposite;
static volatile uint32_t usb_hid_send_ok;

/* The device HID class callback */
usb_status_t USB_DeviceHidGenericCallback(class_handle_t handle, uint32_t event, void *param)
{
    usb_status_t error = kStatus_USB_Error;

    switch (event)
    {
        case kUSB_DeviceHidEventSendResponse:
            {
                usb_hid_send_ok = 1;
            }
            break;
        case kUSB_DeviceHidEventRecvResponse:
            {
                usb_device_endpoint_callback_message_struct_t *msg = (usb_device_endpoint_callback_message_struct_t *)param;
                if(msg->length <= FS_HID_GENERIC_INTERRUPT_OUT_PACKET_SIZE)
                {
                    USB_DeviceHIDReceiveData(msg->buffer,msg->length);
                }
            }
            break;
        case kUSB_DeviceHidEventGetReport:
        case kUSB_DeviceHidEventSetReport:
        case kUSB_DeviceHidEventRequestReportBuffer:
            error = kStatus_USB_InvalidRequest;
            break;
        case kUSB_DeviceHidEventGetIdle:
        case kUSB_DeviceHidEventGetProtocol:
            break;
        case kUSB_DeviceHidEventSetIdle:
            {
                USB_DeviceHidRecv(handle, USB_HID_GENERIC_ENDPOINT_OUT,
                             (uint8_t *)hid_rec_buffer,
                             FS_HID_GENERIC_INTERRUPT_OUT_PACKET_SIZE);
            }
            break;
        case kUSB_DeviceHidEventSetProtocol:
            break;
        default:
            break;
    }

    return error;
}



/* The device callback */
usb_status_t USB_DeviceHidGenericSetConfigure(class_handle_t handle, uint8_t configure)
{
    return kStatus_USB_Success;
}

/* Set interface */
usb_status_t USB_DeviceHidGenericSetInterface(class_handle_t handle, uint8_t interface, uint8_t alternateSetting)
{
    return kStatus_USB_Success;
}
/* Initialize the HID mouse */
usb_status_t USB_DeviceHidGenericInit(usb_device_composite_struct_t *deviceComposite)
{
    s_UsbDeviceComposite       = deviceComposite;
    return kStatus_USB_Success;
}

usb_status_t USB_DeviceHidStartRecv(void)
{
    return USB_DeviceHidRecv(s_UsbDeviceComposite->hidDevice.hidHandle, USB_HID_GENERIC_ENDPOINT_OUT,
                 (uint8_t *)hid_rec_buffer,
                 FS_HID_GENERIC_INTERRUPT_OUT_PACKET_SIZE);

}

usb_status_t USB_DeviceHidStartSend(uint8_t *buffer,uint32_t length)
{
    while(length)
    {
        usb_hid_send_ok = 0 ;
        USB_DeviceHidSend(s_UsbDeviceComposite->hidDevice.hidHandle,USB_HID_GENERIC_ENDPOINT_IN,(uint8_t *)buffer,FS_HID_GENERIC_INTERRUPT_IN_PACKET_SIZE);
        while(!usb_hid_send_ok);
        buffer += FS_HID_GENERIC_INTERRUPT_IN_PACKET_SIZE;
        length -= (length >= FS_HID_GENERIC_INTERRUPT_IN_PACKET_SIZE) ? FS_HID_GENERIC_INTERRUPT_IN_PACKET_SIZE : length;
    }
    return kStatus_USB_Success;
}

__WEAK void USB_DeviceHIDReceiveData(uint8_t *buffer,uint32_t length)
{
    USB_DeviceHidStartRecv();
}

#endif
